package gui;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import simplex.Simplex;

public class MainWindow extends JFrame {

	private JPanel targetPanel;
	private JPanel conditionsPanel;
	private ArrayList<JTextField> targetConds;
	private JComboBox<String> minMax;
	private Map<Integer, ArrayList<JTextField>> map;
	private ArrayList<JComboBox<String>> minMaxConds;
	private JButton calculateAll;
	private JButton calculateStep;
	private JLabel targetLabel;
	private JLabel condsLabel;

	private LogFrame logs;

	Simplex simplex;

	public MainWindow() {
		int targetVariables = Integer.parseInt(JOptionPane.showInputDialog(MainWindow.this, "Podaj ilość zmiennych"));
		int condsCount = Integer.parseInt(JOptionPane.showInputDialog(MainWindow.this, "Podaj ilość ograniczeń"));
		
		setLayout(null);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setTitle("Metoda simplex");
		setSize(800, 600);
		initComboBoxes(condsCount);
		initTargetArray(targetVariables);
		initMap(targetVariables + 1, condsCount);
		addTargetPanel();
		addCondsPanel();
		initLabels();
		initButtons();
	}

	private void initButtons() {
		calculateAll = new JButton("Oblicz wszystko");
		calculateStep = new JButton("Oblicz krokowo");
		add(calculateStep);
		add(calculateAll);
		calculateStep.setBounds(100, 450, 150, 30);
		calculateAll.setBounds(280, 450, 150, 30);
		calculateStep.addActionListener(new ButtonListener("calculateStep"));
		calculateAll.addActionListener(new ButtonListener("calculateAll"));
	}

	private void initLabels() {
		targetLabel = new JLabel("Funkcja celu");
		add(targetLabel);
		targetLabel.setBounds(30, 30, 400, 30);
		condsLabel = new JLabel("Ograniczenia");
		add(condsLabel);
		condsLabel.setBounds(30, 150, 400, 30);
	}

	private void addCondsPanel() {
		int panelSize = 0;
		conditionsPanel = new JPanel();
		conditionsPanel.setLayout(null);
		conditionsPanel.setPreferredSize(new Dimension(110 * map.get(0).size(),
				40 * map.size()));
		JScrollPane bar = new JScrollPane(conditionsPanel);
		bar.setPreferredSize(new Dimension(800, 50 * map.size()));
		add(bar);
		bar.setBounds(0, 190, 800, 200);
		for (int j = 0; j < map.size(); j++) {
			panelSize = 0;
			ArrayList<JTextField> a = map.get((Integer) j);
			for (int i = 0; i < a.size(); i++) {
				JLabel tmp;
				if (i == a.size() - 1) {
					conditionsPanel.add(minMaxConds.get(j));
					minMaxConds.get(j).setBounds(panelSize + 30, (30 * j) + 10,
							100, 25);
					JTextField tf = a.get(i);
					conditionsPanel.add(tf);
					tf.setBounds((100 * i) + 150, (30 * j) + 10, 60, 25);
				} else {
					if (i == a.size() - 2) {
						tmp = new JLabel("x" + (i + 1));
					} else {
						tmp = new JLabel("x" + (i + 1) + " + ");
					}
					JTextField tf = a.get(i);
					conditionsPanel.add(tf);
					tf.setBounds(100 * i, (30 * j) + 10, 60, 25);
					conditionsPanel.add(tmp);
					tmp.setBounds(100 * i + 65, (30 * j) + 10, 55, 25);
					panelSize += 100;
				}
			}

		}

	}

	private void addTargetPanel() {
		int panelSize = 0;
		targetPanel = new JPanel();
		targetPanel.setLayout(null);
		targetPanel
				.setPreferredSize(new Dimension(110 * targetConds.size(), 40));
		JScrollPane bar = new JScrollPane(targetPanel);
		bar.setPreferredSize(new Dimension(800, 50));
		add(bar);
		bar.setBounds(0, 70, 800, 60);
		for (int i = 0; i < targetConds.size(); i++) {
			JLabel tmp;
			if (i == targetConds.size() - 1) {
				tmp = new JLabel("x" + (i + 1) + "    -- > ");
			} else {
				tmp = new JLabel("x" + (i + 1) + " + ");
			}
			JTextField tf = targetConds.get(i);
			targetPanel.add(tf);
			tf.setBounds(100 * i, 10, 60, 25);
			targetPanel.add(tmp);
			tmp.setBounds(100 * i + 65, 10, 55, 25);
			panelSize += 100;
		}

		targetPanel.add(minMax);
		minMax.setBounds(panelSize + 30, 10, 100, 25);
	}

	private void initTargetArray(int variables) {
		targetConds = new ArrayList<JTextField>();
		for (int j = 0; j < variables; j++) {
			JTextField tmp = new JTextField();
			targetConds.add(tmp);
		}
	}

	private void initMap(int variables, int count) {
		map = new HashMap<Integer, ArrayList<JTextField>>();
		for (int i = 0; i < count; i++) {
			ArrayList<JTextField> tmpArray = new ArrayList<JTextField>();
			for (int j = 0; j < variables; j++) {
				JTextField tmp = new JTextField();
				tmpArray.add(tmp);
			}
			map.put((Integer) i, tmpArray);
		}
	}

	private void initComboBoxes(int count) {
		minMax = new JComboBox<String>();
		minMax.addItem("Minimum");
		minMax.addItem("Maximum");
		minMaxConds = new ArrayList<JComboBox<String>>();
		for (int i = 0; i < count; i++) {
			JComboBox<String> tmp = new JComboBox<String>();
			tmp.addItem("<=");
			tmp.addItem(">=");
			tmp.addItem("=");
			minMaxConds.add(tmp);
		}
	}

	private class ButtonListener implements ActionListener {

		private String source;
		private boolean firstStep = true;

		private ButtonListener(String s) {
			super();
			source = s;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO Auto-generated method stub

			if (source.equals("calculateStep")) {
				if (logs instanceof LogFrame) {
					if (!logs.isVisible()) {
						logs.setVisible(true);
					} else {
						if (minMax.getSelectedIndex() == 0) {
							simplex = new Simplex(getOgrValues(),
									getTargetValues(), true, logs.getArea(), true);
							EventQueue.invokeLater(new Runnable() {
								public void run() {
									SimplexTable st = new SimplexTable(simplex, true, logs);
									st.setVisible(true);
									dispose();
								}
							});
						} else {
							simplex = new Simplex(getOgrValues(),
									getTargetValues(), false, logs.getArea(),true);
							EventQueue.invokeLater(new Runnable() {
								public void run() {
									SimplexTable st = new SimplexTable(simplex, true, logs);
									st.setVisible(true);
									dispose();
								}
							});
						}
					}
				} else {
					EventQueue.invokeLater(new Runnable() {
						public void run() {
							logs = new LogFrame();
							logs.setVisible(true);
							simplex = new Simplex(getOgrValues(),
									getTargetValues(), minMax.getSelectedIndex()==0? true:false, logs.getArea(), true);
							SimplexTable st = new SimplexTable(simplex, true, logs);
							st.setVisible(true);
							dispose();
						}
					});
				}
			} else if (source.equals("calculateAll")) {
				if (logs instanceof LogFrame) {
					EventQueue.invokeLater(new Runnable() {
						public void run() {
							if (minMax.getSelectedIndex() == 0) {
								simplex = new Simplex(getOgrValues(),
										getTargetValues(), true, logs.getArea(),false);
								SimplexTable st = new SimplexTable(simplex, false, logs);
								st.setVisible(true);
								simplex.firstSimplex();
								st.setModel();
								dispose();
							} else {
								simplex = new Simplex(getOgrValues(),
										getTargetValues(), false, logs.getArea(),false);
								SimplexTable st = new SimplexTable(simplex, false, logs);
								st.setVisible(true);
								simplex.firstSimplex();	
								st.setModel();
								dispose();
							}
						}
					});
				} else {
					EventQueue.invokeLater(new Runnable() {
						public void run() {
							logs = new LogFrame();
							logs.setVisible(true);
							if (minMax.getSelectedIndex() == 0) {
								simplex = new Simplex(getOgrValues(),
										getTargetValues(), true, logs.getArea(),false);
								SimplexTable st = new SimplexTable(simplex, false, logs);
								st.setVisible(true);
								simplex.firstSimplex();
								st.setModel();
								dispose();
							} else {
								simplex = new Simplex(getOgrValues(),
										getTargetValues(), false, logs.getArea(),false);
								SimplexTable st = new SimplexTable(simplex, false, logs);
								st.setVisible(true);
								simplex.firstSimplex();	
								st.setModel();
								dispose();
							}
						}
					});
				}
			}
		}

		private ArrayList<double[]> getOgrValues() {
			ArrayList<double[]> result = new ArrayList<double[]>();
			double[] tmp;
			try {
				for (int j = 0; j < map.size(); j++) {
					ArrayList<JTextField> tmpArray = map.get((Integer) j);
					tmp = new double[tmpArray.size() + 1];
					for (int i = 0; i < tmpArray.size(); i++) {
						if (tmpArray.get(i).getText().equals("")) {
							tmp[i] = 0;
						} else {
							if (i == (tmpArray.size() - 1)) {
								tmp[i + 1] = Double.parseDouble(tmpArray.get(i)
										.getText());
							} else {
								tmp[i] = Double.parseDouble(tmpArray.get(i)
										.getText());
							}
						}
					}
					if (minMaxConds.get(j).getSelectedIndex() == 0) {
						tmp[tmp.length - 2] = -1.99;
					} else if (minMaxConds.get(j).getSelectedIndex() == 1) {
						tmp[tmp.length - 2] = 1.99;
					} else {
						tmp[tmp.length - 2] = 1.99;
					}
					result.add(tmp);
				}
			} catch (NumberFormatException e) {
				JOptionPane.showMessageDialog(MainWindow.this,
						"Wpisano niepoprawną wartość", "Błąd",
						JOptionPane.ERROR_MESSAGE);
			}
			return result;
		}

		// Sprawdzanie wszystkich pól tekstowych funkcji celu
		private double[] getTargetValues() {
			try {
				double[] tmp = new double[targetConds.size()];
				for (int i = 0; i < targetConds.size(); i++) {
					if (targetConds.get(i).getText().equals("")) {
						tmp[i] = 0;
					} else {
						tmp[i] = Double.parseDouble(targetConds.get(i)
								.getText());
					}
				}
				return tmp;
			} catch (NumberFormatException e) {
				JOptionPane.showMessageDialog(MainWindow.this,
						"Wpisano niepoprawną wartość", "Błąd",
						JOptionPane.ERROR_MESSAGE);
				return new double[0];
			}
		}

	}

}
